package cn.bigfire.wedesk.net.handler;

import cn.bigfire.wedesk.bean.Wedesk;
import cn.bigfire.wedesk.net.protocol.CmdMapper;
import cn.bigfire.wedesk.net.protocol.Protocol;
import cn.hutool.core.lang.Console;
import cn.hutool.core.lang.Pair;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;

import java.lang.reflect.Method;


public class ClientHandler extends SimpleChannelInboundHandler<Protocol> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Protocol msg) throws Exception {
        processMsg(ctx, msg);
    }

    //业务线程池处理消息
    public void processMsg(ChannelHandlerContext ctx, Protocol protocol) {
        Pair<Method, Object> pair = CmdMapper.methodMapper.get(protocol.getCmd());
        if (protocol.getType() == Wedesk.Type.TYPE_Err.getValue()) {
            System.err.println(Console.where() + "协议号:" + protocol.getCmd() + "返回错误信息:" + JSON.toJSONString(protocol.getObj()));
            return;
        }
        if (pair==null){
            System.err.println(Console.where() + "不能处理的协议号:" + protocol.getCmd());
            return;
        }
        Method method = pair.getKey();
        Object actionObj = pair.getValue();
        if (method == null || actionObj == null) {
            System.err.println(Console.where() + "方法调用失败method:" + method + ",actionObj:" + actionObj);
            return;
        }
        //参数处理----------------------------------------------------------------------------------------------
        Class<?>[] paramTypes = method.getParameterTypes();//参数类型
//        Parameter[] parameters = method.getParameters();//参数名称（编译器会把参数名称修改未arg0,arg1这样的参数名，所以此方法不保险）
        //SpringMVC 的方法
        ParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
        String[] parameterNames = discoverer.getParameterNames(method);

        Object[] params = new Object[paramTypes.length];//参数具体值
        for (int i = 0; i < paramTypes.length; i++) {
            Class<?> clazz = paramTypes[i];
            if (ChannelHandlerContext.class.equals(clazz)) {//1.注入ChannelHandlerContext类型参数
                params[i] = ctx;
            } else if (Channel.class.equals(clazz)) {//2.注入Channel类型参数
                params[i] = ctx.channel();
            }  else if (protocol.getObj() != null) {//4.协议中的对象
                try {
//                    String name = parameters[i].getName();
                    if (parameterNames == null || parameterNames[i] == null) {
                        continue;
                    }
                    String name = parameterNames[i];
                    if (protocol.getObj() instanceof JSONObject) {//4.1 JSONObject类型
                        JSONObject jsonObject = (JSONObject) protocol.getObj();
                        if (jsonObject.containsKey(name)) {
                            params[i] = jsonObject.getObject(name, clazz);//如果是内部对象 解构注入
                        } else {
                            params[i] = jsonObject.toJavaObject(clazz);//JSONObject转对象
                        }
                    } else if (protocol.getObj() instanceof JSONArray) {//4.2 JSONArray 转泛型List<Obj>
                        JSONArray jsonArray = (JSONArray) protocol.getObj();
                        params[i] = jsonArray.toJavaList(clazz);
                    } else if (clazz.equals(protocol.getObj().getClass())) {//4.3 对象类型 匹配正确直接填充
                        params[i] = protocol.getObj();
                    } else {//4.3.3 尝试解构 object对象内的字段进行注入,根据[参数名]和对象内[字段]匹配，自动解构注入
                        JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(protocol.getObj()));
                        if (jsonObject.containsKey(name)) {
                            params[i] = jsonObject.get(name);
                        } else {
                            params[i] = jsonObject.toJavaObject(clazz);//JSONObject转对象
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        //----------------------------------------------------------------------------------------------
        try {
            Object returnObj = method.invoke(actionObj, params);//执行Action逻辑
            //----------------------------------------------------------------------------------------------------
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("连接");

    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("断开");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
    }

}
